﻿#include "StdAfx.h"
#include "BaseQuery.h"

//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
FSecure::C3::Core::BaseQuery::BaseQuery(std::weak_ptr<DeviceBridge> sender)
	: m_ReceivedOrWillBeSent(true)
	, m_SequenceNumber(0)	/// THIS IS WRONG
	, m_SenderChannel(sender)
{
	// TODO, parse query.
}

//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
FSecure::C3::Core::BaseQuery::BaseQuery(ResponseType responseType)
	: m_ReceivedOrWillBeSent(false)
	, m_SequenceNumber(GenerateSequenceNumber())
	, m_ResponseType(responseType)
{

}

//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void FSecure::C3::Core::BaseQuery::SetResponseType(ResponseType responseType)
{
	m_ResponseType = responseType;
}

//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
FSecure::ByteVector FSecure::C3::Core::BaseQuery::CompileQueryHeader() const
{
	if (m_ResponseType == ResponseType::None)
		return ByteVector{}.Write(GetProcedureNumber());

	return ByteVector{}.Write(~GetProcedureNumber(), BuildSequenceNumberField(static_cast<std::uint8_t>(m_ResponseType)));
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
std::uint8_t FSecure::C3::Core::BaseQuery::BuildSequenceNumberField(std::uint8_t statusBits) const
{
	return (m_SequenceNumber & (3 << s_SequenceNumberBitLength)) & (statusBits << s_SequenceNumberBitLength);
}

//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
FSecure::C3::Core::BaseQuery::SequenceNumberFieldUnderlyingType FSecure::C3::Core::BaseQuery::GenerateSequenceNumber()
{
	static std::mutex accessMutex;
	std::scoped_lock lock(accessMutex);

	static SequenceNumberFieldUnderlyingType nextGlobalSequenceNumber = 0;
	if (nextGlobalSequenceNumber & (3 << s_SequenceNumberBitLength))
		return nextGlobalSequenceNumber = 0;

	return nextGlobalSequenceNumber++;
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
std::weak_ptr<FSecure::C3::Core::DeviceBridge> FSecure::C3::Core::BaseQuery::GetSenderChannel()
{
	return m_SenderChannel;
}
